<!--
 * @Author: typ
 * @Date: 2025-01-15 10:15:08
 * @LastEditors: typ
 * @LastEditTime: 2025-02-27 10:33:13
 * @FilePath: /720Manage-vite/src/views/model3D/modelView.vue
 * @Description: 3D模型展示页面
-->
<template>
  <!-- 模型项容器 -->
  <div class="model-item">
    <div class="model-title">{{ form.name }}</div>
    <!-- Three.js渲染容器 -->
    <div id="model-viewer" ref="modelContainer" v-loading="loading" element-loading-text="模型加载中..."
      element-loading-background="rgba(0, 0, 0, 1)"></div>
  </div>
</template>

<script setup>
// 导入Vue组合式API相关
import { onMounted, onBeforeUnmount, ref } from 'vue';
import { useRoute } from 'vue-router'
// 导入Three.js核心库
import * as THREE from 'three'
// 导入GLTF模型加载器
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { getModel, getModelTaskById, getModelByTaskId } from '@/api/model';
// 创建模型容器的ref引用
const modelContainer = ref(null)
const route = useRoute()
const loading = ref(true)
const model = ref({})
const form = ref({})
// 声明Three.js相关变量
let scene, camera, renderer, controls

// 组件挂载时的处理
onMounted(() => {
  getData();
  window.addEventListener('resize', handleResize) // 添加窗口大小变化监听
})

// 获取数据
const getData = async () => {
  loading.value = true;
  initThree();
}
// 初始化Three.js场景的函数
const initThree = async () => {
  const modelData = await getModelByTaskId(route.query.id);
  form.value = modelData.data;
  // console.log('modelData', modelData)
  model.value = modelData.data;
  if (modelData.data?.previewFileName) {
    model.value = JSON.parse(modelData.data.previewFileName);
  }
  console.log('model', model.value)
  loading.value = true;
  const newUrl = await getModel({ originalName: model.value.gltf[0] });
  const newBinUrl = await getModel({ originalName: model.value.bin[0] });
  const newImgUrl = await getModel({ originalName: model.value.jpg[0] });
  // 创建Three.js场景
  scene = new THREE.Scene()
  // 设置场景背景色（当前已注释）
  // scene.background = new THREE.Color('#fff');

  // 创建透视相机
  camera = new THREE.PerspectiveCamera(
    55, // 视野角度
    modelContainer.value.clientWidth / modelContainer.value.clientHeight, // 宽高比
    0.1, // 近平面
    1000 // 远平面
  )
  // 设置相机初始位置
  camera.position.z = 5

  // 创建WebGL渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true }) // 启用抗锯齿
  // 设置渲染器尺寸
  renderer.setSize(modelContainer.value.clientWidth, modelContainer.value.clientHeight)
  // 将渲染器的canvas添加到DOM中
  modelContainer.value.appendChild(renderer.domElement)

  // 创建轨道控制器
  controls = new OrbitControls(camera, renderer.domElement)
  // 启用阻尼效果
  controls.enableDamping = true
  // 添加自动旋转
  controls.autoRotate = true  // 启用自动旋转
  controls.autoRotateSpeed = 2.0  // 设置旋转速度，默认为2.0
  controls.enableDamping = true   // 启用阻尼效果使旋转更平滑

  // 添加环境光源
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 白色环境光，强度0.5
  scene.add(ambientLight)

  // 添加平行光源
  const directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 白色平行光，强度1
  directionalLight.position.set(2, 2, 5) // 设置光源位置
  scene.add(directionalLight)

  // 创建GLTF加载器实例
  const loader = new GLTFLoader();

  // 设置加载管理器来处理相对路径
  const manager = new THREE.LoadingManager();
  manager.setURLModifier((res) => {
    if (res.endsWith('.bin')) {
      return newBinUrl
    } else if (res.indexOf('quality') > -1) {
      return newImgUrl
    }
    return res
  });

  loader.manager = manager;

  // 加载GLTF模型
  loader.load(
    newUrl,
    (gltf) => {
      scene.add(gltf.scene)
      // 计算模型包围盒
      const box = new THREE.Box3().setFromObject(gltf.scene)
      const center = box.getCenter(new THREE.Vector3())
      const size = box.getSize(new THREE.Vector3())
      // 计算最大尺寸
      const maxDim = Math.max(size.x, size.y, size.z)
      // 调整相机位置
      camera.position.z = maxDim * 2
      // 设置控制器目标点
      controls.target.copy(center)
      controls.update()
    },
    (xhr) => {
      const progress = Math.floor((xhr.loaded / xhr.total) * 100);
      console.log(`模型加载进度: ${progress}%`);
      loading.value = false;
    },
    (error) => {
      console.error('错误:', error)
    }
  )

  // 创建动画循环函数
  const animate = () => {
    requestAnimationFrame(animate)
    controls.update() // 这行代码会处理自动旋转
    renderer.render(scene, camera)
  }
  animate() // 启动动画循环
}

// 处理窗口大小变化的函数
const handleResize = () => {
  if (!camera || !renderer || !modelContainer.value) return
  // 更新相机宽高比
  camera.aspect = modelContainer.value.clientWidth / modelContainer.value.clientHeight
  // 更新相机投影矩阵
  camera.updateProjectionMatrix()
  // 更新渲染器尺寸
  renderer.setSize(modelContainer.value.clientWidth, modelContainer.value.clientHeight)
}

// 组件卸载前的清理工作
onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize) // 移除窗口大小变化监听
  if (renderer) {
    renderer.dispose() // 释放渲染器资源
    modelContainer.value?.removeChild(renderer.domElement) // 移除canvas元素
  }
})
</script>

<style lang="scss" scoped>
// 模型项样式
.model-item {
  width: 100%;
  height: 100%;
  position: relative;
}

.model-title {
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 10px;
  position: absolute;
  color: #fff;
  top: 20px;
  left: 20px;
}

// Three.js渲染容器样式
#model-viewer {
  width: 100%;
  height: 100vh; // 视口高度减去200px
  background-color: #f0f0f0; // 背景色
}
</style>
